package cn.caplike.demo.nio._2021.buffer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

/**
 * Description: Buffer's Scattering (来自一个 Channel 的数据读到多个 Buffer 之中) And Gathering.
 * <br>telnet localhost 18899
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2022-01-18 12:44
 */
public class BufferScatteringAndGathering {

    public static void main(String[] args) throws IOException {
        int messageLength;
        ByteBuffer[] buffers;
        SocketChannel socketChannel;
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            InetSocketAddress address = new InetSocketAddress(18899);
            serverSocketChannel.socket().bind(address);

            messageLength = 2 + 3 + 4;
            buffers = new ByteBuffer[3];
            buffers[0] = ByteBuffer.allocate(2);
            buffers[1] = ByteBuffer.allocate(3);
            buffers[2] = ByteBuffer.allocate(4);

            socketChannel = serverSocketChannel.accept();
        }

        //noinspection InfiniteLoopStatement
        while (true) {
            int bytesRead = 0;

            // 如果读到的字节数小于总共能读的数据数
            while(bytesRead < messageLength) {
                long r = socketChannel.read(buffers); // !
                bytesRead += r; // 实际读到的字节信息

                System.out.println("bytesRead: " + bytesRead);

                Arrays.stream(buffers)
                    .map(buffer -> "position: " + buffer.position() + ", limit: " + buffer.limit())
                    .forEach(System.out::println);
            }

            // 3个byteBuffer都被读满了
            Arrays.stream(buffers).forEach(ByteBuffer::flip);
            long bytesWritten = 0;
            while (bytesWritten < messageLength) {
                long r = socketChannel.write(buffers);
                bytesWritten += r;
            }

            Arrays.stream(buffers).forEach(ByteBuffer::clear);
            System.out.println("bytesRead: " + bytesRead + ", bytesWritten: " + bytesWritten + ", messageLength: " + messageLength);
        }
    }
}
